/*************************************************************************
	> File Name: include/test.h
	> Author: Wang Bo
	> Mail: 1276106221@qq.com
	> Created Time: 2020年11月07日 星期六 20时57分00秒
 ************************************************************************/

#ifndef _TEST_H
#define _TEST_H
#include <include/linklist.h>

#define COLOR(a, b) "\033[" #b "m" a "\033[0m"
#define COLOR_HL(a, b) "\033[1;" #b "m" a "\033[0m"

#define GREEN(a) COLOR(a, 32)
#define RED(a) COLOR(a, 31)
#define YELLOW(a) COLOR(a, 33)
#define BLUE(a) COLOR(a, 34)
#define PURPLE(a) COLOR(a, 35)

#define GREEN_HL(a) COLOR_HL(a, 32)
#define RED_HL(a) COLOR_HL(a, 31)
#define YELLOW_HL(a) COLOR_HL(a, 33)
#define BLUE_HL(a) COLOR_HL(a, 34)
#define PURPLE_HL(a) COLOR(a, 35)

#define TEST(a, b)\
void a##_mytest_##b();\
__attribute__((constructor))\
void add##_mytest_##a##_mytest_##b() {\
    add_function(a##_mytest_##b, #a "_mytest_" #b);\
}\
void a##_mytest_##b()

#define Type(a) _Generic((a),\
    int : "%d",\
    double : "%lf",\
    float : "%f",\
    long long : "%lld",\
    const char * : "%s",\
    char * : "%s"\
)

#define P(a, color) {\
    char frm[1000];\
    sprintf(frm, color("%s"), Type(a));\
    printf(frm, a);\
}

#define EXPECT(a, b, cmp) {\
mytest_info.total += 1;\
__typeof(a) _a = (a);\
__typeof(b) _b = (b);\
if (_a cmp _b) mytest_info.success += 1;\
else {\
    printf(YELLOW_HL("\n\t%s:%d: failure\n"), __FILE__, __LINE__);\
    printf(YELLOW_HL("\t\texpect: " #a " " #cmp " " #b "\n\t\tactual: "));\
    P(_a, YELLOW_HL);\
    printf(YELLOW_HL(" vs "));\
    P(_b, YELLOW_HL);\
    printf("\n\n");\
}\
printf(GREEN("[-----------] "));\
printf("%s %s %s\t%s\n", #a, #cmp, #b, (a) cmp (b) ? GREEN_HL("True") : RED_HL("False"));\
}

#define EXPECT_EQ(a, b) EXPECT(a, b, ==)
#define EXPECT_NE(a, b) EXPECT(a, b, !=)
#define EXPECT_LT(a, b) EXPECT(a, b, <)
#define EXPECT_GT(a, b) EXPECT(a, b, >)
#define EXPECT_LE(a, b) EXPECT(a, b, <=)
#define EXPECT_GE(a, b) EXPECT(a, b, >=)

typedef void (*TestFuncT)();

typedef struct Function {
    TestFuncT func;
    const char *str;
    struct LinkNode p;
} Function;

struct TestInfo {
    int total, success;
};
extern struct TestInfo mytest_info;

int RUN_ALL_TEST();
void add_function(TestFuncT, const char *);
#endif
